//camera.c, camera system
//1. handles moving the foreground layer relative to sonics position
//2. handles scrolling variables for the background layer depending on level (there shall be a default case as well for future extensions)
//==..restricting this scrolling with the level boundaries array
#include <stdio.h>
#include "camera.h"
#include "object.h"

#define COMPILE_PC

#define LONGTOWORD HIWORD
#define HIWORD LEFTRADIXLONG
#define LOWORD RIGHTRADIXLONG
#define LEFTRADIXLONG(val) ((val & 0xFFFF0000) >> 16)                          //for fixed point numbers (grabs integer portion)
#define RIGHTRADIXLONG(val) (val & 0x0000FFFF)                                 //for fixed point numbers (grabs fractional portion)

#define FIXEDPTTOINT SWAPLONG                                                  //since the integer portion of a fixed point long is the left word, swapping this value to the right word then yields a normal integer value  
#define FIXEDPTTOWORD FIXEDPTTOINT
#define WORDTOLONG(val) (val<<16)
#define SWAPLONG(val) (((val&0xFFFF0000) >> 16) + ((val&0x0000FFFF) << 16))    


#ifdef COMPILE_GEN

#define ENDIANSWAPWORD(val) (val<<8)                                           //shifts right byte half of word "val" 8bits over to left byte half (swaps endianness of values <= 255)
#define SWAPWORDTOFIXEDPT(val) (val<<8)                                        //shifts left byte in right word half (w/swapped endianness) of long "val" 8bits over to left word half to yield the proper fixed-point representation
#define WORDTOFIXEDPT(val) (val<<16)

#endif

#ifdef COMPILE_PC

#define ENDIANSWAPWORD(val) (val<<8)                                           
#define SWAPWORDTOFIXEDPT(val) (val<<8)                                        
#define WORDTOFIXEDPT(val) (val<<16)

#endif


int pcstartlocIndex; //used by StartLocation macro

void (*bgScrollMethodIndex[0xF])(word,word);
void (*bgDeformMethodIndex[0xF])();

word v_scrposy_dup, FFFFF618;  //=FFFFF70C; (v_scrposy_dup+2, bg vertical scroll)
word v_scrposx_dup, FFFFF61C;
word FFFFF61E, FFFFF620;       //=FFFFF718;

long v_hscrolltablebuffer[512];
long *cameraGetHScrollTable() { return v_hscrolltablebuffer; }


signed long v_screenposx;   //ONLY UPPER WORD HALF IS USED, SWAPPED TO LOWER HALF WHEN DOING MATHS
signed long v_screenposy;   //ONLY UPPER WORD HALF IS USED, SWAPPED TO LOWER HALF WHEN DOING MATHS

word v_limitleft1, v_limitleft2, v_limitleft3;
word v_limitright1, v_limitright2;
word v_limittop1, v_limittop2;
word v_limitbtm1, v_limitbtm2;

signed short v_scrshiftx;     //swapped endianness..

word v_lookshift;      //if want to get orig code working change to normal non-extern
bool f_nobgscroll;

word v_bgscroll1, v_bgscroll2, v_bgscroll3;
bool f_bgscrollvert;

LevelSizeIndex LevelSizeArray[0xFF];
StartLocationIndex StartLocArray[0xFF];

#define player objects[0]
extern object *objects;

extern word v_dle_routine;
extern word v_lastlamp;
extern word f_demo;


//RAM BUFFER VALUES USED BY DeformLayers
//$F700-$F701	 Plane A x-position a.k.a v_screenposx
//$F704-$F705	 Plane A y-position a.k.a v_screenposy
//$F708-$F709	 Plane B x-position
//$F70C-$F70D	 Plane B y-position
signed long FFFFF708;   //bg layer sect 1 x pos
signed long FFFFF70C;   //bg layer sect 1 y pos
signed long FFFFF710;   //bg layer sect 2 x pos
signed long FFFFF714;   //bg layer sect 2 y pos
signed long FFFFF718;   //bg layer sect 3 x pos
signed long FFFFF71C;   //bg layer sect 3 y pos

long FFFFF730;
long FFFFF73C;

//RAM BUFFER VALS USED BY LevelSizeLoad
byte FFFFF740;
byte FFFFF741;
byte FFFFF746;
byte FFFFF748;

//scroll flags
byte FFFFF74A;   //flag set for every other 16x16 x-wise based on SCREEN X position
byte FFFFF74B;   //flag set for every other 16x16 y-wise based on SCREEN Y position
byte FFFFF74C;   //flag set for every other 16x16 x-wise based on block section 1
byte FFFFF74D;   //flag set for every other 16x16 y-wise based on block section 1
byte FFFFF74E;

long FFFFF75A;

//loop tile IDs
byte v_256loop1;
byte v_256loop2;
byte v_256roll1;
byte v_256roll2;


//render limits
word FFFFF7F0;   
word FFFFF7F2;
word FFFFF7F4;
word FFFFF7F6;

void StartLocation(byte *startloc) {
     StartLocArray[pcstartlocIndex].x=(startloc[0]<<8)+startloc[1]; 
     StartLocArray[pcstartlocIndex].y=(startloc[2]<<8)+startloc[3]; 
     pcstartlocIndex++;
}

byte LoopTileNums[4*7] = { 		
//loop	loop	tunnel	tunnel
0xB5,	0x7F,	0x1F,	0x20,	//; Green Hill
0x7F,	0x7F,	0x7F,	0x7F,	//; Labyrinth
0x7F,	0x7F,	0x7F,	0x7F,	//; Marble
0xAA,	0xB4,	0x7F,	0x7F,	//; Star Light
0x7F,	0x7F,	0x7F,	0x7F,	//; Spring Yard
0x7F,	0x7F,	0x7F,	0x7F,	//; Scrap Brain
0x7F,	0x7F,	0x7F,	0x7F	//; Ending (Green Hill)
};


void LevelSizeLoad(word v_zone)
{
     FFFFF740=0;
     FFFFF741=0;
     FFFFF746=0;
     FFFFF748=0;
     v_dle_routine=0;
     
     LevelSizeIndex sizeIndex = LevelSizeArray[v_zone];//*12];// 12 bytes large
     FFFFF730 = sizeIndex.FFFFF730val;
     
     v_limitleft2 = sizeIndex.v_limitleft;
     v_limitright2 = sizeIndex.v_limitright; //these 2 assignments a single long transfer in the ROM, important because v_limitright2 might appear nonexistant at first
     v_limitleft1 = sizeIndex.v_limitleft;
     v_limitright1 = sizeIndex.v_limitright; //.....
     
     v_limittop2 = sizeIndex.v_limittop;       
     v_limitbtm2 = sizeIndex.v_limitbtm;     //.....
     v_limittop1 = sizeIndex.v_limittop;
     v_limitbtm1 = sizeIndex.v_limitbtm;     //......
     
     v_limitleft3 = v_limitleft2 + 576;
     
     FFFFF74A=16;
     FFFFF74B=16;
     
     v_lookshift=sizeIndex.v_lookshift;
     
 //---------------------
 
     //LevelSz_ChkLamp
     if (v_lastlamp != 0)
     {
        //Lamp_LoadInfo
        word d1 = player.X;
        word d0 = player.Y;
     }
     else
     {
        StartLocationIndex startIndex = StartLocArray[v_zone]; //*44 bytes large//2 words
        if (f_demo)
        {
         //additional functions for demo mode           
        }
        player.X = startIndex.x;
        player.Y = startIndex.y;
     }
     
     signed short d1 = (player.X - 160);
     if (d1<0) { d1=0; }
     
     //SetScr_WithinLeft
     signed short d2 = v_limitright2;
     if (d2 < d1) { d1 = d2; }
     
     //SetScr_WithinRight
     v_screenposx = WORDTOLONG(d1);
     signed short d0 = (player.Y - 96);
     if (d0 < 0) { d0 = 0; }
     
     //SetScr_WithinTop
     if (v_limitbtm2 < d0)
         d0 = v_limitbtm2;
     
     //SetScr_WithinBottom
     v_screenposy = WORDTOLONG(d0);
     
     
     bgScrollSpeed(d0, d1, v_zone);
     
     v_256loop1 = LoopTileNums[v_zone*4];
     v_256loop2 = LoopTileNums[(v_zone*4)+1];   

     //LevSz_Unk (loads render/draw limits)
     LevelRenderLimitsLoad(v_zone);

}

//dword_61B4:
long renderLimits[] = { 0x00700100, 0x01000100,
		        0x08000100, 0x01000000,
		        0x08000100, 0x01000000,
		        0x08000100, 0x01000000,
		        0x08000100, 0x01000000,
		        0x08000100, 0x01000000,
		        0x00700100, 0x01000100 };

//zonewarning dword_61B4,8
 
void LevelRenderLimitsLoad(word v_zone)   //LevSz_Unk:
{
    //moveq	#0,d0
    //move.b	(v_zone).w,d0
    //lsl.w	#3,d0
    //lea	dword_61B4(pc,d0.w),a1
    long *zoneRenderLimits = &renderLimits[v_zone*2];

    //lea	($FFFFF7F0).w,a2
    //move.l	(a1)+,(a2)+
    FFFFF7F0 = HIWORD(zoneRenderLimits[0]);
    FFFFF7F2 = LOWORD(zoneRenderLimits[0]);

    //move.l	(a1)+,(a2)+
    FFFFF7F4 = HIWORD(zoneRenderLimits[1]);
    FFFFF7F6 = LOWORD(zoneRenderLimits[1]);
  
    //rts
}	

//; ===========================================================================

		
//initializes starting x/y position for each scrolling BG block section
//(dependent on zone)
void bgScrollSpeed(word d0, word d1, word v_zone)
{
     v_lastlamp=0;
     if (v_lastlamp==0)
     {
          FFFFF70C = WORDTOLONG(d0);       //block sect1 y position
          FFFFF714 = WORDTOLONG(d0);       //block sect2/3 y position
          FFFFF708 = WORDTOLONG(d1);       //block sect1 x position
          FFFFF710 = WORDTOLONG(d1);       //block sect2/3 x position
          FFFFF718 = WORDTOLONG(d1);       //?
     }
     word d2=v_zone;                //*2;   unneeded in this case
     (*bgScrollMethodIndex[d2])(d0,d1);  //run the respective scrolling function for this zone
          
}

void pcScrolling()
{
     //http://stackoverflow.com/questions/252748/how-to-use-array-of-function-pointers
     //BINGOOOO
     //bgScrollMethodIndex=new void*[0xF];
     //bgDeformMethodIndex=new void*[0xF];
     bgScrollMethodIndex[0]=BgScroll_GHZ;
     bgScrollMethodIndex[1]=BgScroll_LZ;
     bgScrollMethodIndex[2]=BgScroll_MZ;
     bgScrollMethodIndex[3]=BgScroll_SLZ;
     bgScrollMethodIndex[4]=BgScroll_SYZ;
     bgScrollMethodIndex[5]=BgScroll_SBZ;
     bgScrollMethodIndex[6]=BgScroll_End;
     bgDeformMethodIndex[0]=Deform_GHZ;

}

void BgScroll_GHZ(word d0, word d1)
{
     Deform_GHZ();
}

void BgScroll_LZ(word d0, word d1)
{
     FFFFF70C=d0*2;
}

void BgScroll_MZ(word d0, word d1)
{
     //no scrolling for MZ...
}

void BgScroll_SLZ(word d0, word d1)
{
     FFFFF70C=(d0*2)+0xC0;
}

void BgScroll_SYZ(word d0, word d1)
{
     word d2;
     d2=d0*8;
     d0=d0*16;
     d0=d0+d2;
     d0=d0*256;
     FFFFF70C=d0;
     FFFFF714=d0;
}

void BgScroll_SBZ(word d0, word d1)
{
     d0=d0*8*2*256;
     FFFFF70C=d0;
}

void BgScroll_End(word d0, word d1)
{
     FFFFF70C=0x1E;
     FFFFF714=0x1E;
}

void DeformLayers(word v_zone)
{
    if (f_nobgscroll==0)
    {
         v_bgscroll1=0;
         v_bgscroll2=0; 
         v_bgscroll3=0;
         FFFFF75A=0;          
    
         ScrollHoriz();
         ScrollVertical();
         //DynamicLevelEvents();
         
         v_scrposx_dup=LONGTOWORD(v_screenposx);
         v_scrposy_dup=LONGTOWORD(v_screenposy);   //sent to VSRAM as Y foreground scroll offset
         
         FFFFF61C=LONGTOWORD(FFFFF708);
         FFFFF618=LONGTOWORD(FFFFF70C);            //sent to VSRAM as Y background scroll offset
         FFFFF620=LONGTOWORD(FFFFF718);
         FFFFF61E=LONGTOWORD(FFFFF71C);
         
         word d0=v_zone; //*2;  also unneeded in this case :)    high as fuckkkkkkkk -5/05/2012 5:11 P.M
         (*bgDeformMethodIndex[d0])();  //run the respective background deformation/sub scrolling function for this zone
    }
}

void ScrollHoriz()
{
    //move.w	(v_screenposx).w,d4 ; save old screen position
    word oldScreenX = LONGTOWORD(v_screenposx);          //save old screen X position, as MoveScreenHoriz will change it
		
    //bsr.s	MoveScreenHoriz                          //MoveScreenHoriz will:
    MoveScreenHoriz();                                   //shift v_screenposx (screen x position) based on sonics offset from the middle box 
		                                         //also update v_scrshiftx (diff endian!) with this shift  
    //move.w	(v_screenposx).w,d0
    //andi.w	#$10,d0                        
    word d0 = LONGTOWORD(v_screenposx) & 16;             //
		
    //move.b	($FFFFF74A).w,d1
    byte d1 = FFFFF74A;
    
    //eor.b	d1,d0
    d0 = d0 ^ d1;
		
    //bne.s	locret_65B0                              
    if (d0==0)                  //these values updated only by scrolling increments of 16?
    {
        //eori.b	#$10,($FFFFF74A).w             
        FFFFF74A=FFFFF74A^16;
        
        //move.w	(v_screenposx).w,d0             
        //sub.w	d4,d0		; compare new with old screen position, v_screenposx changed in movescreenhoriz
  	signed short screenShift = LONGTOWORD(v_screenposx) - oldScreenX;
        
        //bpl.s	SH_Forward
        if (screenShift < 0)
            //bset	#2,(v_bgscroll1).w ; screen moves backward
            v_bgscroll1|=4;
            //rts
        else	
            //SH_Forward:
            //bset	#3,(v_bgscroll1).w ; screen moves forward
            v_bgscroll1|=8;
    }
}     

void MoveScreenHoriz()      //this code explained in sonic physicsguide
{
    signed short newScreenX;

    //MoveScreenHoriz:			; XREF: ScrollHoriz
    //move.w	(v_player+obX).w,d0
    //sub.w	(v_screenposx).w,d0 ; Sonic's distance from left edge of screen
    signed short leftEdgeDistance = player.X - LONGTOWORD(v_screenposx);
		
    //subi.w	#144,d0		; is distance less than 144px?
    signed short midLDistance = leftEdgeDistance - 144;  //calculate distance from left side of invisible 16px middle screen box
                                                         //(neg=to the left, pos=to the right)
    //bcs.s	SH_BehindMid	; if yes, branch
    if (midLDistance < 0)                                //if player is to the left of the middle box
    {
        //the code for SH_BehindMid:
        //SH_BehindMid:
    	//add.w	(v_screenposx).w,d0
    	newScreenX = midLDistance + LONGTOWORD(v_screenposx); //screen position will shift left by this distance
            
        //cmp.w	(v_limitleft2).w,d0
        //bgt.s	SH_SetScreen
    	if (newScreenX < v_limitleft2)                   //if this new shifted position is past the left of the left bound
            //move.w	(v_limitleft2).w,d0
    	    newScreenX = v_limitleft2;                   //shifted position is reset at left bound, should not shift any further..
	    //bra.s	SH_SetScreen
    }
    else                                                 //otherwise player is either inside or to the right of middle box...
    { 
        //subi.w	#16,d0		; is distance more than 160px?
        signed short midRDistance = midLDistance - 16;   //calculate distance from right side of invisible 16px middle screen box
                                                         //(neg=to the left [IN THE BOX], pos=to the right)
        //bcc.s	SH_AheadOfMid	; if yes, branch
    	if (midRDistance <= 0)                           //if player is in the middle 16pix box,  (> 144 pix)(at this point in code) and  (< 160 pix)
        {
            //clr.w	(v_scrshiftx).w
            v_scrshiftx = 0;                             //then screen does not shift at this point
            return;
        }
        else                                             //otherwise player is to the right of middle box
        {	
            //; ===========================================================================
            //SH_AheadOfMid:
            //cmpi.w	#16,d0		; is Sonic within 16px of middle area?
            //bcs.s	SH_Ahead16	; if yes, branch
            if (midRDistance > 16)                       //if player more than 16 pixels past the right of the middle area
                //move.w	#16,d0	; set to 16 if greater
                midRDistance = 16;                       //then reset back at 16, as screen never shifts more than 16pixels right in one frame
            
            //SH_Ahead16:
            //add.w	(v_screenposx).w,d0
            newScreenX = midRDistance + LONGTOWORD(v_screenposx); //screen position will shift right by this distance
                
            //cmp.w	(v_limitright2).w,d0
            //blt.s	SH_SetScreen
            if (newScreenX >= v_limitright2)            //if this new shifted position is past the right of the right bound
                //move.w	(v_limitright2).w,d0
                newScreenX = v_limitright2;             //shifted position is reset at right bound, should not shift any further..
        }
    }
    
    //SH_SetScreen:
    //move.w	d0,d1
      //signed short screenShiftBuf = screenShift;
		
    //sub.w	(v_screenposx).w,d1
    //asl.w	#8,d1
      //signed short screenShift = (screenShiftBuf - v_screenposx) << 8;
    signed short screenShift = ((newScreenX - LONGTOWORD(v_screenposx)) << 8);
    
    //move.w	d0,(v_screenposx).w ; set new screen position
    v_screenposx = WORDTOLONG(newScreenX);                    //finally new screen position can be set

    //move.w	d1,(v_scrshiftx).w ; set distance for screen movement
    v_scrshiftx = screenShift;                     //

}
void Deform_GHZ()         //the initial case is here for GHZ calls its deformation routine in place of the scroll routine
{
        //screenShift represents the lower word fractional portion in some fractional value..
        //fractional values work as such: [where IIII is the upper word integer portion, and FFFF the lower word fractional portion]
        //   IIIIFFFF = IIII + (FFFF / 0x10000)
        //
        //the higher byte portion of screenShift represents the number of pixels moved x-wise if the screen has shifted
        //meaning the current fraction in screenShift is calculated by:
        //   (VV00 / 0x10000) = ((pixels moved * 256)/65536) = (pixels moved/256) = 1/256 of pixels moved

        //move.w	(v_scrshiftx).w,d4
        signed short screenShift = v_scrshiftx;

        //multiplying any value by screenShift would be equivalent to: [where pix is number of pixels moved and val is the value]
        // ((1/256)pix) * val 
        //
        //multiplying 96 by screenShift results in:
        //((1/256)pix) * 96 = (96/256)pix = (3/8)pix
        //
        //the fractional value shiftX is then created to represent 3/8ths of the shift in pixels (and fractions of an additional pixel)
	//ext.l	d4        (extending to a long means for pix>8/3 that there will be an integer portion in the value)
	//asl.l	   #5,d4    d4=...
        //move.l   d4,d1    d1=(v_scrshiftx*32)
        //asl.l	   #1,d4    d4=(v_scrshiftx*32)*2=(v_scrshiftx*64)
        //add.l	   d1,d4    d4=(v_scrshiftx*32) + ((v_scrshiftx*64)) = (v_scrshiftx*96)
        signed long shiftX = screenShift * 96;  
        
        
        //longd4=((longd4&0xFFFF0000)>>16);
        
        
        //moveq	#0,d5
	long shiftY=0;
	
	//bsr.w	ScrollBlock1 at this point it is assumed that ScrollBlock1 recieves d1&d5and possibly d4 as args
	ScrollBlock1(shiftX, shiftY);     //adds d4 to FFFFF708, PLANE B, BLOCKSECT1 X POSITION
		                          //adds d5 to FFFFF70C, PLANE B, BLOCKSECT1 Y POSITION [d5=0 in this case, so nothing happens y value then is actually set by scrollblock3 further on...]
                                          //FFFFF74C set on for every other 16x16...
                                          //sets v_bgscroll2 flags accordingly based on sign of scrshift
        //bsr.w	ScrollBlock4
	ScrollBlock4();                   //adds screen shift to FFFFF710, block sect 2/3 x position 
		                          //also flops FFFFF74E based on a scaled and shifted screen y value
		                          //sets v_bgscroll2 flags accordingly based on sign of scrshift
        
        //lea	(v_hscrolltablebuffer).w,a1
	//tmp=v_hscrolltablebuffer
		
        //move.w	(v_screenposy).w,d0
	//andi.w	#$7FF,d0
	//lsr.w	#5,d0
        signed short screenY32 = ( (LONGTOWORD(v_screenposy) & 0x7FF) / 32 );  //range 0 - 64

	//neg.w	d0
	//addi.w	#$26,d0
        signed short screenY32flip = (38 - screenY32);                         //range 38 - (-26)   (screen shift value?)

	//move.w	d0,($FFFFF714).w
        FFFFF714 = WORDTOLONG(screenY32flip);     //block sect 2/3 y position, 38 at v_screenposy 0, 14 at v_screenposy 768

        //move.w	d0,d4
	signed short _screenY32flip = screenY32flip;                  //d4 also this value
        
        //bsr.w	ScrollBlock3                //           sets block sect 1 y position to same as block sect 2/3 y position
	ScrollBlock3(screenY32flip);        //           also handles the respective scrolling flags
		
        //move.w	($FFFFF70C).w,($FFFFF618).w
	FFFFF618 = LONGTOWORD(FFFFF70C);                  //this is sent to VSRAM during a vblank, for background scroll
		
        //move.w	#$6F,d1
	//sub.w	d4,d1
	signed short d1 = (0x6F) - _screenY32flip;       //length of block section, 0x6F-FFFFF714, FFFFF714 is the calculated y position of either block sections 
        
        //---------------------------------------
        #define HI(val) (val<<16)
        #define LO(val) val
        #define NEGHI(val) (HI(-val)&0xFFFF0000) 
        #define NEGLO(val) (LO(-val)&0x0000FFFF) 
       
        //move.w	(v_screenposx).w,d0
        //cmpi.b	#id_Title,(v_gamemode).w
	//bne.s	loc_633C
	//moveq	#0,d0
        //----------if (v_gamemode==id_Title) { d0=0; }
        //loc_633C:
	//neg.w	d0
	//swap	d0
        //move.w	($FFFFF708).w,d0
        //neg.w	d0
        
	signed short hiWord = LONGTOWORD(v_screenposx);         //first half of what gets but in first section of v_hscrolltablebuffer
        signed short loWord = LONGTOWORD(FFFFF708);
        long scrollValue = HI(hiWord) + NEGLO(loWord);          //d0 = (h scroll table buffer index FFBB, FF=foreground offset, BB=bacground offset
        
        int iter=0;
        for (int index=0; index<=d1; index++) 
        {
            //loc_6346:           
            //move.l	d0,(a1)+   
            v_hscrolltablebuffer[iter++] = scrollValue; 
            //dbf	d1,loc_6346
        }
        
        //move.w	#$27,d1
	d1=39; //0x27
        
        //move.w	($FFFFF710).w,d0
	//neg.w	d0
        loWord = LONGTOWORD(FFFFF710);
        scrollValue = HI(hiWord) + NEGLO(loWord);          //d0 = (h scroll table buffer index FFBB, FF=foreground offset, BB=bacground offset
        
        int oldindex2;
        for (int index2=0; index2<=d1; index2++)  //index2 here because we want the original index as additional offset
        {
            //loc_6356:
	    //move.l	d0,(a1)+
            v_hscrolltablebuffer[iter++] = scrollValue;

            //dbf	d1,loc_6356
        }
        
        //FOR THE 3D PARALLAX EFFECT ON THE WATER:

        //block section 2 scrolls against the screen, just as the foreground layer does
        //however the fg scrolls at a much slower rate, approx 128x slower, therefore accumulating distance from section 2
        //the plain distance from fg can be used, 
        //however to make things a bit more interesting (perspective-wise),
        //this distance is measured from 512 pixels -behind- the screen
  
        //move.w	($FFFFF710).w,d0
	//addi.w	#0,d0
        signed short sectionX = LONGTOWORD(FFFFF710);
        //long scrollValue = HI(hiWord) + LO(loWord);          //d0 = (h scroll table buffer index FFBB, FF=foreground offset, BB=bacground offset
  
        //move.w	(v_screenposx).w,d2
	//addi.w	#-$200,d2
	//sub.w	d0,d2
        signed short distScreenXfromSectX = ( (LONGTOWORD(v_screenposx) - 512) - sectionX );
        
        //then a fraction of this distance (1/104th) is taken..
        //   (between bitshifts to the left to keep precision, as this is stored in different endianness)

	//ext.l	d2
	//asl.l	#8,d2
        //divs.w	#$68,d2
	//ext.l	d2
	//asl.l	#8,d2
	signed long d2=( (distScreenXfromSectX << 8) / 104) << 8;   //relative to a fraction of 2nd/3rd block sections x position and also screen x
		
        //nextScroll is then slowly decumlated with this fraction for each line,
        // allowing each line to move slightly faster than the next below it,
        // (which a skewed line when looking at the starting points of each line, whose slope is determined by this fraction)
        //
	//moveq	#0,d3
	//move.w	d0,d3
	signed long nextScroll = sectionX;
        
        //move.w	#$47,d1
	//add.w	d4,d1                                                                                                                                                                                                                                                                                                 
	d1 = _screenY32flip + 71;           //count here is 71+(scaled screen Y value, to trim the bottom sections
        
        for (int index3=0; index3<=d1; index3++)
        {
        //loc_6384:
        //	move.w	d3,d0
        //	neg.w	d0
                scrollValue = HI(hiWord) + NEGLO(nextScroll);

        //    	move.l	d0,(a1)+
                v_hscrolltablebuffer[iter++] = scrollValue; 
                //printf("d0=%i\n", d0);
                //printf("v_hscrolltablebuffer[%i]=%i\n", index3+oldindex2+oldindex, v_hscrolltablebuffer[index3+oldindex2+oldindex]);

        	//swap	d3
        	//add.l	d2,d3
                //swap	d3
        	nextScroll = SWAPLONG(SWAPLONG(nextScroll)+d2); //d2 is the scaled 3rd section value here
        		
                //dbf	d1,loc_6384
        }
}

		//rts	
//; End of function Deform_GHZ

void ScrollBlock1(long shiftX, long shiftY)     //initial case is d4=v_scrshift*96, d5=0, called by deform ghz
{
    //ScrollBlock1:				; XREF: Deform_GHZ; et al
    //move.l	($FFFFF708).w,d2
    signed long oldSectionX = FFFFF708;             //PLANE B sect 1 X POSITION
        
    //move.l	d2,d0    
    //add.l	d4,d0
    signed long newSectionX = oldSectionX + shiftX;
		
    //move.l	d0,($FFFFF708).w
    FFFFF708 = newSectionX;                 //PLANE B X updated with v_scrshift*96, change in screen position

    //-------------		    //move.l	d0,d1
    //swap	d1
    //andi.w	#$10,d1
    signed short xOffset16 = LONGTOWORD(newSectionX) & 16;  //swap for bg index and get 0-15=0,16-31=16,tile offset
        
    //move.b	($FFFFF74C).w,d3  //upper left half?
    byte flagSetRange = FFFFF74C;          
    
    //eor.b	d3,d1
    xOffset16 = xOffset16 ^ flagSetRange;
        
    //bne.s	loc_679C
    if (xOffset16 == 0)        //if 0 or 16
    {
        
        //eori.b	#$10,($FFFFF74C).w        FFFFF74C=FFFFF74C^16;           //add 16 if 0 or subtract 16 if 16
	
        //sub.l	d2,d0
	//D0 FROM HEREON REFERS TO INITIAL SHIFT		
        long _shiftX = newSectionX - oldSectionX;                       //MINUS THE ORIG VALUE LEAVES THE INITIAL SHIFT
 
        if (_shiftX < 0)                     //if this is negative
            //bpl.s	loc_6796
            //bset	#2,(v_bgscroll2).w
            v_bgscroll2 |= 4;            //flag for this section of tiles scroll lefr
        else
            //loc_6796:
            //bset	#3,(v_bgscroll2).w
            v_bgscroll2 |= 8;            //flag for this section of tiles scroll right
    }
    //---------------

    //loc_679C:
    //move.l	($FFFFF70C).w,d3
    signed long oldSectionY = FFFFF70C; //plane b sect 1 y position
		
    //move.l	d3,d0		
    //add.l	d5,d0
    signed long newSectionY = oldSectionY + shiftY;
		
    //move.l	d0,($FFFFF70C).w
    FFFFF70C = newSectionY;    //update plane b sect1 y-position add d5 offset
		
    //--------------
    //move.l	d0,d1
    //swap	d1
    //andi.w	#$10,d1
    signed short yOffset16 = LONGTOWORD(newSectionY) & 16;
        
    //move.b	($FFFFF74D).w,d2
    flagSetRange = FFFFF74D;

    //eor.b	d2,d1
    yOffset16 = yOffset16 ^ flagSetRange;
		
    //bne.s	locret_67D0
    if (yOffset16 == 0)
    {
        //eori.b	#$10,($FFFFF74D).w
    	FFFFF74D=FFFFF74D^16;
            
        //sub.l	d3,d0
    	long _shiftY = newSectionY - oldSectionY;        //gives initial arg d5
    		
        //bpl.s	loc_67CA
    	if (_shiftY < 0)
            //bset	#0,(v_bgscroll2).w
            v_bgscroll2 |= 1;
        else	
            //; ===========================================================================
            //loc_67CA:
            //bset	#1,(v_bgscroll2).w
            v_bgscroll2 |= 2;
    }            
    //-------------
//locret_67D0:
//rts	
} //; End of function ScrollBlock1


//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

void ScrollBlock2(long shiftX, long shiftY)  //memory based version of scrollblock3
{
    //move.l	($FFFFF708).w,d2
    signed long oldSectionX = FFFFF708;             //PLANE B sect 1 X POSITION
        
    //move.l	d2,d0    
    //add.l	d4,d0
    signed long newSectionX = oldSectionX + shiftX;
		
    //move.l	d0,($FFFFF708).w
    FFFFF708 = newSectionX;                 //PLANE B X updated with v_scrshift*96, change in screen position
    
    //move.l	($FFFFF70C).w,d3
    signed long oldSectionY = FFFFF70C; //plane b sect 1 y position
		
    //move.l	d3,d0		
    //add.l	d5,d0
    signed long newSectionY = oldSectionY + shiftY;
		
    //move.l	d0,($FFFFF70C).w
    FFFFF70C = newSectionY;    //update plane b sect1 y-position add d5 offset
    //move.l	d0,d1
    //swap	d1
    //andi.w	#$10,d1
    signed short yOffset16 = LONGTOWORD(newSectionY) & 16;
        
    //move.b	($FFFFF74D).w,d2
    byte flagSetRange = FFFFF74D;

    //eor.b	d2,d1
    yOffset16 = yOffset16 ^ flagSetRange;
		
    //bne.s	locret_67D0
    if (yOffset16 == 0)
    {
        //eori.b	#$10,($FFFFF74D).w
    	FFFFF74D=FFFFF74D^16;
            
        //sub.l	d3,d0
    	long _shiftY = newSectionY - oldSectionY;        //gives initial arg d5
    		
        //bpl.s	loc_680C
    	if (_shiftY < 0)
            //bset	#0,(v_bgscroll2).w
            v_bgscroll2 |= 1;
        else	
            //; ===========================================================================
            //loc_680C:
            //bset	#1,(v_bgscroll2).w
            v_bgscroll2 |= 2;
    }            

//locret_6812:
//		rts	
} //; End of function ScrollBlock2


//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

//SCROLLBLOCK3 IS PASSED A MATHEMATICALLY RECALCULATED VERSION OF SCREEN Y (ALSO AT FFFFF714)
void ScrollBlock3(signed short newSectionY)   //FFFFF74D = (FFFFF74D ^ (FFFFF70C & 16))
{
    //ScrollBlock3:				; XREF: Deform_GHZ; et al
    //move.w	($FFFFF70C).w,d3
    signed short oldSectionY = LONGTOWORD(FFFFF70C);         //vertical scroll value
		
    //move.w	d0,($FFFFF70C).w
    FFFFF70C = WORDTOLONG(newSectionY);                     //sets vertical scroll value with func arg
		
    //move.w	d0,d1
    //andi.w	#$10,d1
    signed short yOffset16 = newSectionY & 16;           //0 or 16, current 32 position 0-15, 16-31? odd or even 16x16 y-wise
		
    //move.b	($FFFFF74D).w,d2
    byte flagSetRange = FFFFF74D;                //set below 
		
    //eor.b	d2,d1
    yOffset16 = yOffset16 ^ flagSetRange;                        //
		
    //bne.s	locret_6842
    if (yOffset16 == 0)                       //if on an even 16x16 for the first time sincelast call
    {
        //eori.b	#$10,($FFFFF74D).w        FFFFF74D = FFFFF74D ^ 16;         //SET OR RESET NYBBLE I.E. 00 BECOMES 10 / 10 BECOMES 00
           
        //sub.w	d3,d0
        signed short shiftY = newSectionY - oldSectionY;
		   
        if (shiftY < 0)
            //bpl.s	loc_683C
            //bset	#0,(v_bgscroll2).w
            v_bgscroll2 |= 1;                  //these flags then only set for every other 16x16 y-wise..
             //rts	
             //; ===========================================================================
        else
             //loc_683C:
             //bset	#1,(v_bgscroll2).w
            v_bgscroll2 |= 2;
    }
}

//locret_6842:
//		rts	
//; End of function ScrollBlock3


//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//ScrollBlock4:				; XREF: Deform_GHZ
void ScrollBlock4()
{
    //move.w	($FFFFF710).w,d2
    //move.w	($FFFFF714).w,d3
		
    //FFFFF710 = block section 2/3 X
    //FFFFF714 = block section 2/3 Y
    signed short oldSectionX = LONGTOWORD(FFFFF710);         //
    signed short oldSectionY = LONGTOWORD(FFFFF714);     //SET RIGHT AFTER CALL TO THIS (38-((v_screenposy&0x7FF)*32))
		 
    //move.w	(v_scrshiftx).w,d0
    signed short screenShift = v_scrshiftx;

    //ext.l	d0    
    //asl.l	#7,d0
    long shiftX = (screenShift * 128);   //default shift value, 1/2 of shifted screen position
		
    //add.l	d0,($FFFFF710).w
    FFFFF710 = FFFFF710 + shiftX;     //add to previous shift
        
    //move.w	($FFFFF710).w,d0
    //andi.w	#$10,d0
    signed short xOffset16 = LONGTOWORD(FFFFF710) & 16;

    //move.b	($FFFFF74E).w,d1
    byte flagSetRange = FFFFF74E;  
        
    //eor.b	d1,d0
    xOffset16 = xOffset16 ^ flagSetRange;  
        
    //bne.s	locret_6884
    if (xOffset16 == 0)  //if on an even 16x16 for the first time sincelast call
    {
        //eori.b	#$10,($FFFFF74E).w
        FFFFF74E = FFFFF74E ^ 16;   //flop to accomodate condition (^ first timesince last call)
        
        //move.w	($FFFFF710).w,d0
        //sub.w	d2,d0
	signed short _shiftX = LONGTOWORD(FFFFF710) - oldSectionX;    //this is the v_scrshiftx*128 value
		    
        //these flags then only set for every other 16x16 x-wise..
        if (_shiftX < 0)   //if screen moving left
            //bpl.s	loc_687E
            //bset	#2,(v_bgscroll3).w
            v_bgscroll3 |= 4;
            //bra.s	locret_6884
            //; ===========================================================================
            //loc_687E:
        else       //else screen moving right
            //bset	#3,(v_bgscroll3).w
            v_bgscroll3 |= 8;    }
//locret_6884:
//		rts	
}   //; End of function ScrollBlock4

void ScrollVertical()  //handles v_bgscroll1 //6616
{

    //ScrollVertical:				; XREF: DeformLayers
    //moveq	#0,d1
    signed long newScreenY = 0;	                        //here we initialize the value that will hold new Y position
		
    //move.w	(v_player+obY).w,d0
    //sub.w	(v_screenposy).w,d0 ; Sonic's distance from top of screen
    signed short distTop = player.Y - LEFTRADIXLONG(v_screenposy);
		
    //printf("sonics distance from top: %i\n", d0);
    //btst	#2,(v_player+obStatus).w ; is Sonic rolling?
    if ((player.Status & 4) == 4) 
       distTop = distTop - 5;
        //beq.s	SV_NotRolling	; if not, branch
	//subq.w	#5,d0
        
           
    //SV_NotRolling:
		
    //btst	#1,(v_player+obStatus).w ; is Sonic jumping?
    //beq.s	loc_664A	; if not, branch
    if  ((player.Status & 2) == 2)  
    {  
           
        //addi.w	#32,d0
        //sub.w	(v_lookshift).w,d0
	distTop = (distTop + 32) - v_lookshift;  //distance from top border when jumping (64 pix default)
		   
        //bcs.s	loc_6696       ;branch carry on set
	if (distTop < 0)                                //
            ScrollVertical_Check16(newScreenY, distTop);
        else
        {
            //subi.w	#64,d0         ;
	    distTop = distTop - 64;
		      
            //bcc.s	loc_6696       ;branch carry on clear
            if (distTop > 0)			  
                 ScrollVertical_Check16(newScreenY, distTop);
            else
            {
                //tst.b	(f_bgscrollvert).w
                //bne.s	loc_66A8
                if (f_bgscrollvert != 0)
                {
                    ScrollVertical_NoScroll(newScreenY);
                }
                else
                {
                    //loc_6656:
		    //clr.w	($FFFFF73C).w
                    FFFFF73C = 0;    //FFFFF73E = Y CAMERA POSITION, FFFF73C = ADDITIONAL Y OFFSET?
                    //rts
                    return;
                }
            }
        }
    }
    
    //; ===========================================================================
    //loc_664A:
    else       //default case, sonic not jumping    {  
        //sub.w	(v_lookshift).w,d0
	distTop = distTop - v_lookshift;    //update position from top to include lookshift, which is distance above or below center
		
	//bne.s	loc_665C
        if (distTop == 0)		        //if sonic is v_lookshift (96) pixels from top, dead center
        {
    	       //tst.b	(f_bgscrollvert).w
    	       //bne.s	loc_66A8
               if (f_bgscrollvert!=0)
                   ScrollVertical_NoScroll(newScreenY);
               else
               {
                  //loc_6656:
		  //clr.w	($FFFFF73C).w
                  FFFFF73C=0;    //FFFFF73E = Y CAMERA POSITION, FFFF73C = ADDITIONAL Y OFFSET?
                  //rts
                  return;
               }
                  //; ===========================================================================
        }
        //loc_665C:
        else			                       //sonic is above or below center screen
        {
                //cmpi.w	#$60,(v_lookshift).w
                //bne.s	loc_6684
                if (v_lookshift==96)           //if sonic is not lookshifting
                {
                   //move.w	(v_player+obInertia).w,d1
                   signed short absInertia=player.Inertia;               

		   //bpl.s	loc_666C
		   //neg.w	d1
                   if (absInertia<0) { absInertia=-absInertia; }    //absolute value
                                    
                   //loc_666C:
		    //cmpi.w	#$800,d1
		    //bcc.s	loc_6696
		    if (absInertia<=2048)   //if inertia less than 2048, sonic has a valid inertia?
                    {
		         //move.w	   #$600,d1
                         word screenShiftY = ENDIANSWAPWORD(6);    //new y pos                        
                         //cmpi.w	#6,d0
    		         //bgt.s	loc_66F6
    		         if (distTop > 6) { ScrollVertical_Down(newScreenY, screenShiftY); }

                         //cmpi.w	#-6,d0
    		         //blt.s	loc_66C0
                         else if (distTop < -6) { ScrollVertical_Up(newScreenY, screenShiftY); }
                     
                         //bra.s	loc_66AE
                         else { ScrollVertical_AtCenter(newScreenY, distTop); }
                    }
                    else
                    { 
                         ScrollVertical_Check16(newScreenY, distTop);      
                    }
                }
                else            //sonic is currently lookshifting 
                {
                     //; ===========================================================================
                     //loc_6684:
    		     //move.w	#$200,d1
                     word screenShiftY = ENDIANSWAPWORD(2);
                     
                     //cmpi.w	#2,d0
    		     //bgt.s	loc_66F6
    		     if (distTop > 2) { ScrollVertical_Down(newScreenY, screenShiftY); }

                     //cmpi.w	#-2,d0
    		     //blt.s	loc_66C0
                     else if (distTop < -2) { ScrollVertical_Up(newScreenY, screenShiftY); }
                     
                     //bra.s	loc_66AE
                     else { ScrollVertical_AtCenter(newScreenY, distTop); }
                      
                }
//; ===========================================================================

        }
    }

    //move.w	(v_screenposy).w,d4
    word oldScreenY = LONGTOWORD(v_screenposy);
        
    //swap	d1
    newScreenY = WORDTOLONG(newScreenY);
    //move.l	d1,d3
    long d3=newScreenY;
        
    //sub.l	(v_screenposy).w,d3
    //ror.l	#8,d3
    //move.w	d3,($FFFFF73C).w
    FFFFF73C=(d3-v_screenposy)/256;
		
    //move.l	d1,(v_screenposy).w
    v_screenposy=newScreenY;
		
		
    //------the rest here is like in scrollblocks------//
    //move.w	(v_screenposy).w,d0
    //andi.w	#$10,d0
    signed short d0=LONGTOWORD(v_screenposy)&16;
		
    //move.b	($FFFFF74B).w,d1
    byte d1=(byte)FFFFF74B;
        
    //eor.b	d1,d0
    d0=d0^d1;
        
    //bne.s	locret_6766
    if (d0==0)
    {
        //eori.b	#$10,($FFFFF74B).w
        FFFFF74B=FFFFF74B^16;
		  
        //move.w	(v_screenposy).w,d0
        //sub.w	d4,d0
        d0=LEFTRADIXLONG(v_screenposy)-oldScreenY;
        
        //bpl.s	loc_6760        if (d0 < 0)
        //bset	#0,(v_bgscroll1).w
            v_bgscroll1=v_bgscroll1|1;  
              //rts	
              //; ===========================================================================
        else
              //loc_6760:
              //bset	#1,(v_bgscroll1).w
            v_bgscroll1=v_bgscroll1|2; 
    }
    //; ===========================================================================
    
    //locret_6766:
    //		rts	
}   //; End of function ScrollVertical
//-----------------------------------

void ScrollVertical_Check16(long &newScreenY, signed short distTop)
{
     //goto loc_6696;     //sonic moving too fast 
     //loc_6696:          //sonic atmax inertia
                         
     //move.w	#$1000,d1
     word screenShiftY = ENDIANSWAPWORD(16);   //new screen y pos
                //cmpi.w	#$10,d0
     //bgt.s	loc_66F6
     if (distTop > 16) { ScrollVertical_Down(newScreenY, screenShiftY); }

     //cmpi.w	#$-10,d0
     //blt.s	loc_66C0
     else if (distTop < -16) { ScrollVertical_Up(newScreenY, screenShiftY); }
                     
     //bra.s	loc_66AE
     else { ScrollVertical_AtCenter(newScreenY, distTop); }
     //; ===========================================================================
}

void ScrollVertical_NoScroll(long &newScreenY)
{
    //loc_66A8:  //jump straight to here if f_bgscrollvert is a value (non-zero),only when sonic jumps
    //moveq	#0,d0    //move.b	d0,(f_bgscrollvert).w        
    word distTop = 0;			//calculations as if sonic were touching the top
    f_bgscrollvert=0; //(d0)		//clear this flag

    ScrollVertical_AtCenter(newScreenY, distTop);
}

void ScrollVertical_Up(long &newScreenY, word screenShiftY)
{

     
    //loc_66C0:  //straight to here if we are too high above ctr

    //big endian most significant to left

                       

    //neg.w	d1
    //ext.l	d1
    //asl.l	#8,d1
    //add.l	(v_screenposy).w,d1
    newScreenY = (-(SWAPWORDTOFIXEDPT(screenShiftY)) + v_screenposy);       
        
    //swap d1 
    newScreenY = LONGTOWORD(newScreenY);

    ScrollVertical_AboveCenter(newScreenY);
}

void ScrollVertical_Down(long &newScreenY, word screenShiftY)
{
    //loc_66F6:      //jump straight to here if we are too far below the center box
		
    //ext.l	d1
    //asl.l	#8,d1
    //add.l	(v_screenposy).w,d1
    newScreenY = (SWAPWORDTOFIXEDPT(screenShiftY) + v_screenposy);
       
    //swap	d1
    newScreenY = LONGTOWORD(newScreenY);
        
    ScrollVertical_BelowCenter(newScreenY);
}

void ScrollVertical_AtCenter(long &newScreenY, signed short distTop)
{
      //loc_66AE: //straight to here if we are in the ctr
      //moveq	#0,d1
      //move.w	d0,d1      //add.w	(v_screenposy).w,d1
      newScreenY = (distTop + LONGTOWORD(v_screenposy));    //new screen y = distance above/below center + old screen y = total shift
			
      //tst.w	d0
      //bpl.w	loc_6700
      //bra.w	loc_66CC                    //skip the respective camera lag instructions
      if (distTop > 0) { ScrollVertical_BelowCenter(newScreenY); /*goto loc_6700;*/ } //if we are below ctr
      else             { ScrollVertical_AboveCenter(newScreenY); /*goto loc_66CC;*/ } //if we are above ctr

}

void ScrollVertical_AboveCenter(long &newScreenY)
{
//loc_66CC:   

	//cmp.w	(v_limittop2).w,d1
	//bgt.s	loc_6724
              
	if (newScreenY <= v_limittop2)     //if we are above the level top limit
        {
            //printf("4a) (d1&0x0000FFFF)=%04X>v_limittop2=%i, a.k.a camera isnt too far down past its limit v_limittop2\n ", d1&0x0000FFFF, v_limittop2);
            
            //cmpi.w	#-$100,d1
            //bgt.s	loc_66F0

            //
            
            if (newScreenY <= -256)                  //if too high above game top limit
            {

               //andi.w	#$7FF,d1
               newScreenY=newScreenY&0x7FF;          
               
	       //andi.w	#$7FF,(v_player+obY).w
	       player.Y=player.Y&0x7FF;              //LIMIT PLAYER Y
		       
               //andi.w	#$7FF,(v_screenposy).w
	       v_screenposy=SWAPLONG(SWAPLONG(v_screenposy)&0x7FF);      //LIMIT SCREEN Y
		       
               //andi.w	#$3FF,($FFFFF70C).w
	       FFFFF70C=FFFFF70C&0x3FF;              //PLANE B Y-POSITION
               
               //bra.s	loc_6724
               //===========================================================================
           }
           else	//not above game top limit, but above level top limit
           {
                 //loc_66F0:
                 //move.w	(v_limittop2).w,d1
                 newScreenY = v_limittop2;      //reset us at the top
                 //printf("4a) we are below the top limit, reset us at the top limit d1=%08X\n", d1);

                 //bra.s	loc_6724
            }
        }
        else
        {    
                 //bra.s	loc_6724
        }
} //; ===========================================================================


void ScrollVertical_BelowCenter(long &newScreenY)
{
    //loc_6700:     
		
    //cmp.w	(v_limitbtm2).w,d1
    //blt.s	loc_6724
 
    if (newScreenY >= v_limitbtm2)  //if screen is to shift below the bottom limit,
    {
        //printf("d1=%i\n,v_limitbtm2=%i\n",d1&0x0000FFFF,v_limitbtm2);
           
        //subi.w	#$800,d1
        newScreenY = newScreenY - 2048; //
          
        //bcs.s	loc_6720
	if (newScreenY >= 0)   //if we are below game bottom limit
        {
            //andi.w	#$7FF,(v_player+obY).w
            player.Y = player.Y & 0x7FF;       //restrict player Y 
        
            //subi.w	#$800,(v_screenposy).w
	    v_screenposy = SWAPLONG(SWAPLONG(v_screenposy)-0x800);  //and reset back up, this gets changed anyway though d1? pointless
		     
             //andi.w	#$3FF,($FFFFF70C).w
             FFFFF70C = FFFFF70C & 0x3FF;     //PLANE B Y-POSITION
		     
             //printf("player->Y=player->Y&0x7FF=%i, v_screenposy=v_screenposy-2048=%i, FFFFF70C=FFFFF70C&0x3FF=%i\n", player->Y, v_screenposy, FFFFF70C);
             //bra.s	loc_6724
             //; ===========================================================================
        }
        else     //not below game bottom limit but below level bottom limit
        {
                 //loc_6720:
    		     //move.w	(v_limitbtm2).w,d1             
                 newScreenY = v_limitbtm2;           //keep at bottom
                 //printf("4a) we are atbottom?, d1=v_limitbtm2[%08X,%i]\n",d1,v_limitbtm2);
        }
    }
}



byte LevelSizeData[] = {
0x00,0x04,0x00,0x00,0x24,0xbf,0x00,0x00,0x03,0x00,0x00,0x60,0x00,0x04,0x00,
0x00,0x1e,0xbf,0x00,0x00,0x03,0x00,0x00,0x60,0x00,0x04,0x00,0x00,0x29,0x60,
0x00,0x00,0x03,0x00,0x00,0x60,0x00,0x04,0x00,0x00,0x2a,0xbf,0x00,0x00,0x03,
0x00,0x00,0x60,0x00,0x04,0x00,0x00,0x19,0xbf,0x00,0x00,0x05,0x30,0x00,0x60,
0x00,0x04,0x00,0x00,0x10,0xaf,0x00,0x00,0x07,0x20,0x00,0x60,0x00,0x04,0x00,
0x00,0x20,0x2f,0xff,0x00,0x08,0x00,0x00,0x60,0x00,0x04,0x00,0x00,0x20,0xbf,
0x00,0x00,0x07,0x20,0x00,0x60,0x00,0x04,0x00,0x00,0x17,0xbf,0x00,0x00,0x01,
0xd0,0x00,0x60,0x00,0x04,0x00,0x00,0x17,0xbf,0x00,0x00,0x05,0x20,0x00,0x60,
0x00,0x04,0x00,0x00,0x18,0x00,0x00,0x00,0x07,0x20,0x00,0x60,0x00,0x04,0x00,
0x00,0x16,0xbf,0x00,0x00,0x07,0x20,0x00,0x60,0x00,0x04,0x00,0x00,0x1f,0xbf,
0x00,0x00,0x06,0x40,0x00,0x60,0x00,0x04,0x00,0x00,0x1f,0xbf,0x00,0x00,0x06,
0x40,0x00,0x60,0x00,0x04,0x00,0x00,0x20,0x00,0x00,0x00,0x06,0xc0,0x00,0x60,
0x00,0x04,0x00,0x00,0x3e,0xc0,0x00,0x00,0x07,0x20,0x00,0x60,0x00,0x04,0x00,
0x00,0x22,0xc0,0x00,0x00,0x04,0x20,0x00,0x60,0x00,0x04,0x00,0x00,0x28,0xc0,
0x00,0x00,0x05,0x20,0x00,0x60,0x00,0x04,0x00,0x00,0x2c,0x00,0x00,0x00,0x06,
0x20,0x00,0x60,0x00,0x04,0x00,0x00,0x2e,0xc0,0x00,0x00,0x06,0x20,0x00,0x60,
0x00,0x04,0x00,0x00,0x21,0xc0,0x00,0x00,0x07,0x20,0x00,0x60,0x00,0x04,0x00,
0x00,0x1e,0x40,0xff,0x00,0x08,0x00,0x00,0x60,0x00,0x04,0x20,0x80,0x24,0x60,
0x05,0x10,0x05,0x10,0x00,0x60,0x00,0x04,0x00,0x00,0x3e,0xc0,0x00,0x00,0x07,
0x20,0x00,0x60,0x00,0x04,0x00,0x00,0x05,0x00,0x01,0x10,0x01,0x10,0x00,0x60,
0x00,0x04,0x00,0x00,0x0d,0xc0,0x01,0x10,0x01,0x10,0x00,0x60,0x00,0x04,0x00,
0x00,0x2f,0xff,0x00,0x00,0x03,0x20,0x00,0x60,0x00,0x04,0x00,0x00,0x2f,0xff,
0x00,0x00,0x03,0x20,0x00,0x60
};

byte ghzstartloc[] = {
     0x00,0x50,0x03,0xb0
};
//byte ghz2 etc..

void pcStartLocations()   
{
     pcstartlocIndex=0;
     
     //consider http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967
     StartLocation(ghzstartloc);
}



void pcLevelBounds()
{
     //level boundaries data and proper code for integrate this data as if it were part of the executable
     //...to be loaded into the game engine eventually when reaching the proper code
     v_lastlamp=0;
     f_nobgscroll=0;
     
     
     for (int lp=0; lp<28; lp++)
     {      //28 total entries (word, long, long, word)
         LevelSizeArray[lp].FFFFF730val=(LevelSizeData[0+(lp*12)]<<8)+(LevelSizeData[1+(lp*12)]);
         LevelSizeArray[lp].v_limitleft=(LevelSizeData[2+(lp*12)]<<24)+(LevelSizeData[3+(lp*12)]<<16);
         LevelSizeArray[lp].v_limitright=(LevelSizeData[4+(lp*12)]<<8)+(LevelSizeData[5+(lp*12)]);
         LevelSizeArray[lp].v_limittop=(LevelSizeData[6+(lp*12)]<<24)+(LevelSizeData[7+(lp*12)]<<16);
         LevelSizeArray[lp].v_limitbtm=(LevelSizeData[8+(lp*12)]<<8)+(LevelSizeData[9+(lp*12)]);
         LevelSizeArray[lp].v_lookshift=(LevelSizeData[10+(lp*12)]<<8)+(LevelSizeData[11+(lp*12)]);
         //printf("LevelSizeArray[%i].FFFFF730val=%i\n", lp, LevelSizeArray[lp].FFFFF730val);
         //printf("LevelSizeArray[%i].v_limitleft=%i\n", lp, LevelSizeArray[lp].v_limitleft);
         //printf("LevelSizeArray[%i].v_limitright=%i\n", lp, LevelSizeArray[lp].v_limitright);
         //printf("LevelSizeArray[%i].v_limittop=%i\n", lp, LevelSizeArray[lp].v_limittop);
         //printf("LevelSizeArray[%i].v_limitbtm=%i\n", lp, LevelSizeArray[lp].v_limitbtm);
         //printf("LevelSizeArray[%i].v_lookshift=%i\n\n\n", lp, LevelSizeArray[lp].v_lookshift);
     }
     
     
     return;
}
